package com.rq.viewtestapplication.manager;

import android.graphics.Point;
import android.graphics.RectF;
import android.util.SparseIntArray;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import com.rq.viewtestapplication.FeaturePoint;
import com.rq.viewtestapplication.LOG;
import com.rq.viewtestapplication.ViewInfo;

import java.util.ArrayList;
import java.util.List;

import static com.rq.viewtestapplication.ViewInfo.ALIGNING_MIN;

public class ChildManager {
    List<ViewInfo> childInfo = new ArrayList<>();


    public boolean hasNoChild() {
        return childInfo.size() == 0;
    }

    public void init(ViewGroup mindPanViewGroup) {
        int size = mindPanViewGroup.getChildCount();
        if (childInfo.size() == 0 && size > 0) {
            for (int i = size; i > 0; i--) {
                View v = mindPanViewGroup.getChildAt(i - 1);
                this.childInfo.add(size - i, new ViewInfo(v, v.getX(), v.getY(), v.getWidth(), v.getHeight()));
            }
        }
    }

    public void reset() {
        zoomType = -1;
        focusIndex = -1;
    }

    private final static int THRESHOLD_OF_CLOSE_DOT = 30;
    private int zoomType = -1;//1-临近角落  2-触摸点临近边

    public boolean isZoomItem(float x, float y) {
        if (childInfo.size() > 0) {
            float dis = THRESHOLD_OF_CLOSE_DOT;
            int fcus = -1;
            int closeType = -1;
            FeaturePoint point = null;
            for (int i = 0; i < childInfo.size(); i++) {
                ViewInfo info = childInfo.get(i);
                FeaturePoint p = FeaturePoint.generatePoint(info.getView());
                if (disInConnerPoint(x, y, p) < dis) {
                    closeType = 1;
                    point = p;
                    fcus = i;
                    dis = disInConnerPoint(x, y, p);
                } else if (p.closeSide(x, y, dis)) {
                    closeType = 2;
                    point = p;
                    fcus = i;
                }
            }
            if (fcus > -1) {
                zoomType = closeType == 1 ? point.closeTo(new Point((int) x, (int) y), dis)
                        : point.closeSideTag(x, y, dis);
                focusIndex = fcus;
                return true;
            }
        }
        return false;
    }

    /**
     * @param value    原始数据
     * @param velocity 手势速度
     * @param isX      是否获取X轴坐标 false-Y轴坐标
     * @return 子项中接近的坐标值
     */
    private int getCloseSideValue(float value, float velocity, boolean isX) {
        int res = (int) value;
        if (velocity < ViewInfo.SPEED_LIMIT) {
            float dis = ALIGNING_MIN;
            for (int i = 0; i < childInfo.size(); i++) {
                if (i == focusIndex) continue;
                ViewInfo v = childInfo.get(i);
                if (isX) {
                    if (Math.abs(value - v.getLeft()) < dis) {
                        res = v.getLeft();
                        dis = Math.abs(value - v.getLeft());
                    }
                    if (Math.abs(value - v.getRight()) < dis) {
                        res = v.getRight();
                        dis = Math.abs(value - v.getRight());
                    }
                } else {
                    if (Math.abs(value - v.getTop()) < dis) {
                        res = v.getTop();
                        dis = Math.abs(value - v.getTop());
                    }
                    if (Math.abs(value - v.getBottom()) < dis) {
                        res = v.getBottom();
                        dis = Math.abs(value - v.getBottom());
                    }
                }
            }
        }
        return res;
    }

    public void zoomItem(float x, float y, float xVelocity, float yVelocity) {
        LOG.e("ChildManager", "zoomItem.zoomType:" + zoomType);
        LOG.e("ChildManager", "zoomItem.focusIndex:" + focusIndex);
        if (zoomType == -1 || zoomType == 5 || focusIndex == -1) return;
        ViewInfo vInfo = childInfo.get(focusIndex);
//        FeaturePoint point = FeaturePoint.generatePoint(childInfo.get(focusIndex).getView());
//        Point calc = point.getClosedConnerPoint(new Point((int) x, (int) y));
        int l = Integer.MIN_VALUE;
        int t = Integer.MIN_VALUE;
        int r = Integer.MIN_VALUE;
        int b = Integer.MIN_VALUE;
        if (zoomType >= 7) {
            t = getCloseSideValue(y, yVelocity, false);
        } else if (zoomType <= 3) {
            b = getCloseSideValue(y, yVelocity, false);
        }
        if (zoomType % 3 == 1) {
            l = getCloseSideValue(x, xVelocity, true);
        } else if (zoomType % 3 == 0) {
            r = getCloseSideValue(x, xVelocity, true);
        }
        if (l == Integer.MIN_VALUE) l = vInfo.getLeft();
        if (t == Integer.MIN_VALUE) t = vInfo.getTop();
        if (r == Integer.MIN_VALUE) r = vInfo.getRight();
        if (b == Integer.MIN_VALUE) b = vInfo.getBottom();


        if (l > r) {
            l = l + r;
            r = l - r;
            l = l - r;
        }
        if (t > b) {
            t = t + b;
            b = t - b;
            t = t - b;
        }
        vInfo.changeLTRB(l, t, r, b);
    }

    private static float disInConnerPoint(float x, float y, FeaturePoint p) {
        Point calc = p.getClosedConnerPoint(new Point((int) x, (int) y));
        double deltaX = x - calc.x;
        double deltaY = y - calc.y;
        return (float) Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
    }

    private static float disInCenterPoint(float x, float y, FeaturePoint p) {
        Point calc = p.getClosedCenterPoint(new Point((int) x, (int) y));
        double deltaX = x - calc.x;
        double deltaY = y - calc.y;
        return (float) Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
    }

    public List<ViewInfo> getChildInfo() {
        return childInfo;
    }

    public void updateAll() {
        for (int i = 0; i < childInfo.size(); i++) {
            ViewInfo info = childInfo.get(i);
            info.update();
        }
    }

    public void updateFocus() {
        if (focusIndex == -1 || focusIndex >= childInfo.size()) return;
        ViewInfo info = childInfo.get(focusIndex);
        info.update();
    }

    public void moveAll(float x, float y) {
        for (int i = 0; i < childInfo.size(); i++) {
            ViewInfo info = childInfo.get(i);
            info.move(x, y);
        }
    }

    public void moveFocus(float x, float y, float xVelocity, float yVelocity) {
        if (focusIndex == -1) return;
        ViewInfo info = childInfo.get(focusIndex);
        info.move(x, y, xVelocity, yVelocity);
    }

    /**
     * @return 返回聚焦子视图下标 -1 --->    未聚焦子视图
     */
    public int getFocusIndexInView(float x, float y) {
        SparseIntArray res = getEventInViewPositions(x, y);
        if (res.size() > 0) {
            focusIndex = res.get(0);
            return res.get(0);
        }
        return -1;
    }

    public int getFocusIndex() {
        return focusIndex;
    }

    public int getEventInViewOtherIndex(float x, float y) {
        SparseIntArray res = getEventInViewPositions(x, y);
        if (res.size() > 1) {
            for (int i = 1; i < res.size(); i++) {
                if (res.get(i) > focusIndex) {
                    focusIndex = res.get(i);
                    return res.get(i);
                }
            }
            focusIndex = res.get(0);
            return res.get(0);
        }
        return focusIndex;
    }

    public void zoomAll(float newCenterX, float newCenterY, float scale) {
        for (int i = 0; i < childInfo.size(); i++) {
            View v = childInfo.get(i).getView();
            ViewInfo info = childInfo.get(i);
            float x3 = newCenterX - (newCenterX - info.getLeft()) * scale;
            float y3 = newCenterY - (newCenterY - info.getTop()) * scale;
            float w3 = info.getWidth() * scale;
            float h3 = info.getHeight() * scale;
            v.layout((int) x3, (int) y3, (int) (x3 + w3), (int) (y3 + h3));
        }

    }

    public View getFirstFocusView(MotionEvent ev) {
        SparseIntArray res = getEventInViewPositions(ev.getX(), ev.getY());
        if (res.size() > 0) {
            return childInfo.get(res.get(0)).getView();
        }
        return null;
    }

    public SparseIntArray getEventInViewPositions(float x, float y) {
        SparseIntArray res = new SparseIntArray();
        for (int i = 0; i < childInfo.size(); i++) {
            ViewInfo v = childInfo.get(i);
            if (x >= v.getLeft() && x <= v.getRight() && y > v.getTop() && y <= v.getBottom()) {
                res.put(res.size(), i);
            }
        }
        return res;
    }

    public RectF getFocusRect() {
        if (focusIndex == -1) return null;
        View v = childInfo.get(focusIndex).getView();
        return new RectF(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
    }

    public String getChildInfoStr() {
        String all = "";
        for (ViewInfo info : childInfo) {
            all += "child." + info.getView().getTag() + "(" + info.getLeft() + "," + info.getTop() + ")w=" + info.getWidth() + ",h=" + info.getHeight();
            all += "\n";
        }
        return all;
    }

    private int focusIndex = -1;

    public void checkThenReset() {
        focusIndex = -1;
        boolean isAllDismiss = true;
        for (ViewInfo info : childInfo) {
            if (!info.cannotSee()) {
                isAllDismiss = false;
                break;
            }
        }
        if (isAllDismiss) {
            for (ViewInfo info : childInfo) {
                info.reset();
            }
        }
    }

}
